package com.analysis.controller;

import com.analysis.config.SaveReferenceExecutorService;
import com.analysis.dto.*;
import com.analysis.entity.*;
import com.analysis.enums.RequireLogin;
import com.analysis.enums.WebTypeEnum;
import com.analysis.exception.AppBuilderException;
import com.analysis.service.ProductDomainService;
import com.analysis.service.ProjectService;
import com.analysis.service.QuestionService;
import com.analysis.service.ReferencesService;
import com.analysis.services.BrandExposureAnalysisService;
import com.analysis.utils.StringUtil;
import com.analysis.utils.UserUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 品牌曝光量分析控制器
 *
 * @author 蒋棒
 * @date 2025/1/10
 */
@RestController
@RequestMapping("/exposure")
@CrossOrigin(origins = "*")
@Validated
public class BrandExposureController {

    private static final Logger logger = LoggerFactory.getLogger(BrandExposureController.class);

    @Autowired
    private BrandExposureAnalysisService brandExposureAnalysisService;
    @Autowired
    private ProductDomainService productDomainService;
    @Autowired
    private QuestionService questionService;
    @Autowired
    private ReferencesService referencesService;
    @Autowired
    private SaveReferenceExecutorService saveReferenceExecutorService;
    @Autowired
    private ProjectService projectService;

    /**
     * 分析品牌曝光量
     * <p>
     * 该接口用于分析指定产品在AI模型中的曝光情况，包括：
     * 1. 自有产品在各AI模型中的曝光次数
     * 2. 与竞品的对比分析
     * 3. 问题级别的详细曝光统计
     * 4. 品牌排名分析
     *
     * @param request 品牌曝光量分析请求，包含产品名称、竞品列表、问题列表和AI模型列表
     * @return 品牌曝光量分析结果，包含详细的曝光统计和对比数据
     * @throws AppBuilderException 当请求参数无效或分析过程中发生错误时
     */
    @PostMapping("/analyze")
    @RequireLogin
    public ApiResponse<BrandExposureResponse> analyzeBrandExposure(
            @RequestBody BrandExposureRequest request, HttpServletRequest httpServletRequest) {
        long startTime = System.currentTimeMillis();
        String requestId = generateRequestId();
        try {
            // 设置项目
            initProject(request, httpServletRequest);

            // 参数验证
            validateRequest(request);

            // 执行分析
            BrandExposureResponse response = brandExposureAnalysisService.analyzeBrandExposure(
                    request.getOwnProductName(),
                    request.getCompetitorNames(),
                    request.getQuestions(),
                    request.getAiModels()
            );

            // 生成信源信息
            saveDatabase(requestId, request, response);

            return ApiResponse.success(response);
        } catch (IllegalArgumentException e) {
            long duration = System.currentTimeMillis() - startTime;
            logger.warn("品牌曝光量分析请求参数无效 - 请求ID: {}, 耗时: {}ms, 产品: {}, 错误: {}",
                    requestId, duration, request.getOwnProductName(), e.getMessage());
            return ApiResponse.error("400", e.getMessage());
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            logger.error("品牌曝光量分析系统异常 - 请求ID: {}, 耗时: {}ms, 产品: {}, 错误: {}",
                    requestId, duration, request.getOwnProductName(), e.getMessage(), e);
            return ApiResponse.error("500", "系统内部错误，请稍后重试");
        }
    }

    /**
     * 验证请求参数
     *
     * @param request 请求对象
     * @throws IllegalArgumentException 当参数无效时
     */
    private void validateRequest(BrandExposureRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("请求对象不能为空");
        }
        if (StringUtils.isBlank(request.getOwnProductName())) {
            throw new IllegalArgumentException("自有产品名称不能为空");
        }
        if (request.getQuestions() == null || request.getQuestions().isEmpty()) {
            throw new IllegalArgumentException("问题列表不能为空");
        }
        // 验证问题列表中的每个问题
        for (int i = 0; i < request.getQuestions().size(); i++) {
            String question = request.getQuestions().get(i);
            if (StringUtils.isBlank(question)) {
                throw new IllegalArgumentException("第" + (i + 1) + "个问题不能为空");
            }
            if (question.length() > 500) {
                throw new IllegalArgumentException("第" + (i + 1) + "个问题长度不能超过500字符");
            }
        }
        // 验证产品名称长度
        if (request.getOwnProductName().length() > 100) {
            throw new IllegalArgumentException("自有产品名称长度不能超过100字符");
        }
        // 验证竞品名称
        if (StringUtils.isNotBlank(request.getCompetitorNames())) {
            String[] competitors = request.getCompetitorNames().split(",");
            for (String competitor : competitors) {
                if (StringUtils.isNotBlank(competitor) && competitor.trim().length() > 100) {
                    throw new IllegalArgumentException("竞品名称长度不能超过100字符: " + competitor);
                }
            }
        }
    }

    /**
     * 生成请求ID用于追踪
     *
     * @return 请求ID
     */
    private String generateRequestId() {
        return "REQ_" + System.currentTimeMillis() + "_" + Thread.currentThread().getId();
    }

    /**
     * 将问题数据存储到tb_question表
     * 根据product_name和question去重，如果已存在则不新增
     *
     * @param request 品牌曝光分析请求
     */
    private void saveQuestionsToDatabase(BrandExposureRequest request) {
        String productName = request.getOwnProductName();
        String competitorNames = request.getCompetitorNames();
        List<String> questions = request.getQuestions();
        if (questions == null || questions.isEmpty()) {
            return;
        }
        int savedCount = 0;
        int skippedCount = 0;
        for (String question : questions) {
            if (StringUtils.isBlank(question)) {
                continue;
            }
            try {
                // 检查是否已存在相同的product_name和question
                List<Question> existingQuestions = questionService.getQuestionsByProductAndQuestion(productName, question, request.getProjectId());

                if (existingQuestions != null && !existingQuestions.isEmpty()) {
                    // 已存在，跳过
                    skippedCount++;
                } else {
                    // 不存在，创建新记录
                    Question newQuestion = new Question();
                    newQuestion.setProjectId(request.getProjectId());
                    newQuestion.setCompanyId(request.getCompanyId());
                    newQuestion.setProductName(productName);
                    newQuestion.setQuestion(question);
                    newQuestion.setCompetitorName(competitorNames);
                    newQuestion.setEnableStatus(1);
                    int result = questionService.createQuestion(newQuestion);
                    if (result > 0) {
                        savedCount++;
                    }
                }
            } catch (Exception e) {
                logger.error("存储单个问题失败 - 产品: {}, 问题: {}, 错误: {}", productName, question, e.getMessage());
            }
        }
        logger.info("问题存储完成 - 产品: {}, 新增: {}, 跳过: {}, 总计: {}",
                productName, savedCount, skippedCount, questions.size());
    }

    /**
     * 生成信源数据到tb_references表
     * 从ownProductDetailedExposure.details中提取Reference信息，结合BrandExposureRequest数据生成References记录
     *
     * @param request  品牌曝光分析请求
     * @param response 品牌曝光分析响应
     */
    private void saveDatabase(String requestId, BrandExposureRequest request, BrandExposureResponse response) {
        // 异步执行数据库存储操作，不阻塞主流程
        CompletableFuture.runAsync(() -> {
            try {
                saveQuestionsToDatabase(request);
                logger.info("问题数据已存储到数据库 - 请求ID: {}, 产品: {}, 问题数量: {}",
                        requestId, request.getOwnProductName(), request.getQuestions().size());
            } catch (Exception e) {
                logger.warn("存储问题数据到数据库失败 - 请求ID: {}, 产品: {}, 错误: {}",
                        requestId, request.getOwnProductName(), e.getMessage());
            }
        }, saveReferenceExecutorService.getThreadPool());

        CompletableFuture.runAsync(() -> {
            try {
                saveReferencesToDatabase(request, response);
                logger.info("信源数据已生成到数据库 - 请求ID: {}, 产品: {}",
                        requestId, request.getOwnProductName());
            } catch (Exception e) {
                logger.warn("生成信源数据到数据库失败 - 请求ID: {}, 产品: {}, 错误: {}",
                        requestId, request.getOwnProductName(), e.getMessage());
            }
        }, saveReferenceExecutorService.getThreadPool());
    }

    /**
     * 生成信源数据到tb_references表
     * 从ownProductDetailedExposure.details中提取Reference信息，结合BrandExposureRequest数据生成References记录
     * 优化版本：使用批量操作提高执行效率
     *
     * @param request  品牌曝光分析请求
     * @param response 品牌曝光分析响应
     */
    private void saveReferencesToDatabase(BrandExposureRequest request, BrandExposureResponse response) {
        String productName = request.getOwnProductName();
        if (response == null || response.getOwnProductDetailedExposure() == null) {
            logger.warn("响应数据为空，无法生成信源数据 - 产品: {}", productName);
            return;
        }
        
        // 得到官网url
        ProductDomain productDomain = productDomainService.getProductDomainByProductName(request.getOwnProductName());
        String domain = productDomain != null ? productDomain.getDomain() : null;

        // 收集所有需要处理的Reference数据
        List<ReferenceData> referenceDataList = new ArrayList<>();
        int filteredCount = 0;

        // 遍历每个问题的详细曝光数据，收集所有Reference
        for (BrandExposureResponse.QuestionExposureDetail questionDetail : response.getOwnProductDetailedExposure()) {
            String question = questionDetail.getQuestion();
            List<BrandExposureResponse.ModelExposureCount> details = questionDetail.getDetails();
            if (details == null || details.isEmpty()) {
                continue;
            }
            
            // 遍历每个AI模型的详细数据
            for (BrandExposureResponse.ModelExposureCount modelDetail : details) {
                String aiModel = modelDetail.getAiModelName();
                BrandExposureAiCallDTO data = modelDetail.getData();
                if (data == null || data.getReferences() == null || data.getReferences().isEmpty()) {
                    continue;
                }
                
                // 遍历每个Reference，收集数据
                for (Reference reference : data.getReferences()) {
                    if (StringUtils.isBlank(reference.getName()) || StringUtils.isBlank(reference.getUrl())) {
                        continue;
                    }
                    
                    // 校验URL格式，过滤无效URL
                    if (!StringUtil.isValidUrl(reference.getUrl())) {
                        filteredCount++;
                        logger.debug("过滤无效URL - 产品: {}, 问题: {}, AI模型: {}, URL: {}",
                                productName, question, aiModel, reference.getUrl());
                        continue;
                    }

                    // 创建ReferenceData对象
                    ReferenceData refData = new ReferenceData();
                    refData.setUrl(reference.getUrl());
                    refData.setName(reference.getName());
                    refData.setQuestion(question);
                    refData.setAiModel(aiModel);
                    refData.setProductName(productName);
                    refData.setProjectId(request.getProjectId());
                    refData.setCompanyId(request.getCompanyId());
                    refData.setDomain(domain);
                    referenceDataList.add(refData);
                }
            }
        }

        if (referenceDataList.isEmpty()) {
            logger.info("没有有效的信源数据需要处理 - 产品: {}", productName);
            return;
        }

        // 批量处理信源数据
        int generatedCount = 0;
        int skippedCount = 0;
        
        try {
            // 批量检查已存在的URL
            List<String> urls = referenceDataList.stream()
                    .map(ReferenceData::getUrl)
                    .collect(Collectors.toList());
            
            Map<String, References> existingReferencesMap = referencesService.getReferencesByUrls(urls);
            
            // 分离新增和更新的记录
            List<References> newReferencesList = new ArrayList<>();
            List<References> updateReferencesList = new ArrayList<>();
            
            for (ReferenceData refData : referenceDataList) {
                References existingRef = existingReferencesMap.get(refData.getUrl());
                if (existingRef != null) {
                    // 已存在，准备更新引用次数
                    existingRef.setReferenceCount(existingRef.getReferenceCount() + 1);
                    updateReferencesList.add(existingRef);
                    skippedCount++;
                } else {
                    // 不存在，创建新记录
                    References newReference = createNewReference(refData);
                    newReferencesList.add(newReference);
                }
            }
            
            // 批量更新已存在的记录
            if (!updateReferencesList.isEmpty()) {
                int updateCount = referencesService.batchUpdateReferences(updateReferencesList);
                logger.debug("批量更新信源引用次数完成 - 产品: {}, 更新数量: {}", productName, updateCount);
            }
            
            // 批量插入新记录
            if (!newReferencesList.isEmpty()) {
                int insertCount = referencesService.batchCreateReferences(newReferencesList);
                generatedCount = insertCount;
                logger.debug("批量插入新信源完成 - 产品: {}, 插入数量: {}", productName, insertCount);
            }
            
        } catch (Exception e) {
            logger.error("批量处理信源数据失败 - 产品: {}, 错误: {}", productName, e.getMessage(), e);
            // 如果批量操作失败，回退到逐条处理
            generatedCount = 0;
            skippedCount = 0;
            for (ReferenceData refData : referenceDataList) {
                try {
                    References existingRef = referencesService.getReferencesByUrl(refData.getUrl());
                    if (existingRef != null) {
                        existingRef.setReferenceCount(existingRef.getReferenceCount() + 1);
                        referencesService.updateReferences(existingRef);
                        skippedCount++;
                    } else {
                        References newReference = createNewReference(refData);
                        int result = referencesService.createReferences(newReference);
                        if (result > 0) {
                            generatedCount++;
                        }
                    }
                } catch (Exception ex) {
                    logger.error("处理单个信源失败 - URL: {}, 错误: {}", refData.getUrl(), ex.getMessage());
                }
            }
        }

        logger.info("信源生成完成 - 产品: {}, 新增: {}, 跳过: {}, 过滤: {}, 总计: {}",
                productName, generatedCount, skippedCount, filteredCount, generatedCount + skippedCount + filteredCount);
    }

    /**
     * 创建新的References记录
     */
    private References createNewReference(ReferenceData refData) {
        References newReference = new References();
        newReference.setProjectId(refData.getProjectId());
        newReference.setCompanyId(refData.getCompanyId());
        newReference.setWebName(StringUtil.extractDomainFromUrl(refData.getUrl()));
        newReference.setPageName(refData.getName());
        newReference.setUrl(refData.getUrl());
        newReference.setWebType(refData.getDomain() != null && refData.getUrl().contains(refData.getDomain()) 
                ? WebTypeEnum.WEB_SITE.getSource() : WebTypeEnum.THIRD_SITE.getSource());
        newReference.setReferenceCount(1);
        newReference.setAiModel(refData.getAiModel());
        newReference.setAddType(2); // 自动添加
        newReference.setProductName(refData.getProductName());
        newReference.setQuestion(refData.getQuestion());
        newReference.setEnableStatus(1);
        return newReference;
    }

    /**
     * Reference数据封装类
     */
    private static class ReferenceData {
        private String url;
        private String name;
        private String question;
        private String aiModel;
        private String productName;
        private Long projectId;
        private Long companyId;
        private String domain;

        // Getters and Setters
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getQuestion() { return question; }
        public void setQuestion(String question) { this.question = question; }
        public String getAiModel() { return aiModel; }
        public void setAiModel(String aiModel) { this.aiModel = aiModel; }
        public String getProductName() { return productName; }
        public void setProductName(String productName) { this.productName = productName; }
        public Long getProjectId() { return projectId; }
        public void setProjectId(Long projectId) { this.projectId = projectId; }
        public String getDomain() { return domain; }
        public void setDomain(String domain) { this.domain = domain; }

        public Long getCompanyId() {
            return companyId;
        }

        public void setCompanyId(Long companyId) {
            this.companyId = companyId;
        }
    }


    public void initProject(BrandExposureRequest request, HttpServletRequest httpServletRequest) {
        // 设置项目
        User user = UserUtils.getCurrentUser(httpServletRequest);
        Project selectedProject = projectService.getSelectedByCompanyId(user.getCompanyId());
        if (selectedProject == null) {
            throw new IllegalArgumentException("请选择一个项目");
        }
        request.setProjectId(selectedProject.getId());
        request.setCompanyId(user.getCompanyId());
    }

}
